--- /dev/null
+#
+# Copyright (c) 2018, Tano Systems. All Rights Reserved.
+# Copyright (c) 2023-2024. All Rights Reserved.
+#
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=LuCI support for LLDP daemon
+LUCI_DEPENDS:=+lldpd +rpcd-mod-ucode
+
+PKG_LICENSE:=MIT
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
--- /dev/null
+/*
+ * Copyright (c) 2018-2020, Tano Systems LLC. All Rights Reserved.
+ * Copyright (c) 2023-2024. All Rights Reserved.
+ */
+
+'use strict';
+'require ui';
+'require form';
+'require network';
+'require session';
+'require uci';
+
+/*
+ * Filter neighbors (-H)
+ *
+ * The filter column means that filtering is enabled
+ * The 1proto column tells that only one protocol will be kept.
+ * The 1neigh column tells that only one neighbor will be kept.
+ *
+ * incoming outgoing
+ * filter 1proto 1neigh filter 1proto 1neigh
+ * 0
+ * 1 x x x x
+ * 2 x x
+ * 3 x x
+ * 4 x x
+ * 5 x
+ * 6 x
+ * 7 x x x x x
+ * 8 x x x
+ * 9 x x x x
+ * 10 x x
+ * 11 x x
+ * 12 x x x x
+ * 13 x x x
+ * 14 x x x x
+ * 15 x x x
+ * 16 x x x x x
+ * 17 x x x x
+ * 18 x x x
+ * 19 x x x
+ */
+
+const etitle = _('enable filter');
+const ptitle = _('keep only one protocol');
+const ntitle = _('keep only one neighbor');
+
+var cbiFilterSelect = form.Value.extend({
+ __name__: 'CBI.LLDPD.FilterSelect',
+
+ __init__: function() {
+ this.super('__init__', arguments);
+
+ this.selected = null;
+
+ this.filterVal = [
+ [ 0, 0, 0, 0, 0, 0 ],
+ [ 1, 1, 0, 1, 1, 0 ],
+ [ 1, 1, 0, 0, 0, 0 ],
+ [ 0, 0, 0, 1, 1, 0 ],
+ [ 1, 0, 0, 1, 0, 0 ],
+ [ 1, 0, 0, 0, 0, 0 ],
+ [ 0, 0, 0, 1, 0, 0 ],
+ [ 1, 1, 1, 1, 1, 0 ],
+ [ 1, 1, 1, 0, 0, 0 ],
+ [ 1, 0, 1, 1, 1, 0 ],
+ [ 0, 0, 0, 1, 0, 1 ],
+ [ 1, 0, 1, 0, 0, 0 ],
+ [ 1, 0, 1, 1, 0, 1 ],
+ [ 1, 0, 1, 1, 0, 0 ],
+ [ 1, 1, 0, 1, 0, 1 ],
+ [ 1, 1, 0, 1, 0, 0 ],
+ [ 1, 1, 1, 1, 0, 1 ],
+ [ 1, 1, 1, 1, 0, 0 ],
+ [ 1, 0, 0, 1, 0, 1 ],
+ [ 1, 0, 0, 1, 1, 0 ]
+ ];
+ },
+
+ /** @private */
+ handleRowClick: function(section_id, ev) {
+ var row = ev.currentTarget;
+ var tbody = row.parentNode;
+ var selected = row.getAttribute('data-filter');
+ var input = tbody.querySelector('[id="' + this.cbid(section_id) + '-' + selected + '"]');
+
+ this.selected = selected;
+
+ tbody.querySelectorAll('tr').forEach(function(e) {
+ e.classList.remove('lldpd-filter-selected');
+ });
+
+ input.checked = true;
+ row.classList.add('lldpd-filter-selected');
+ },
+
+ formvalue: function(section_id) {
+ return this.selected || this.cfgvalue(section_id);
+ },
+
+ renderFrame: function(section_id, in_table, option_index, nodes) {
+ var tmp = this.description;
+
+ // Prepend description with table legend
+ this.description =
+ '<ul><li>' + 'E — ' + etitle + '</li>' +
+ '<li>' + 'P — ' + ptitle + '</li>' +
+ '<li>' + 'N — ' + ntitle + '</li>' +
+ '</ul>' + this.description;
+
+ var rendered = this.super('renderFrame', arguments);
+
+ // Restore original description
+ this.description = tmp;
+
+ return rendered;
+ },
+
+ renderWidget: function(section_id, option_index, cfgvalue) {
+ //default value is "15" - rows are zero based
+ var selected = parseInt(cfgvalue) || 15;
+
+ var tbody = [];
+
+ var renderFilterVal = L.bind(function(row, col) {
+ return this.filterVal[row][col] ? '✔' : '';
+ }, this);
+
+ for (var i = 0; i < this.filterVal.length; i++) {
+ tbody.push(E('tr', {
+ 'class': ((selected == i) ? 'lldpd-filter-selected' : ''),
+ 'click': L.bind(this.handleRowClick, this, section_id),
+ 'data-filter': i,
+ }, [
+ E('td', {}, [
+ E('input', {
+ 'class': 'cbi-input-radio',
+ 'data-update': 'click change',
+ 'type': 'radio',
+ 'id': this.cbid(section_id) + '-' + i,
+ 'name': this.cbid(section_id),
+ 'checked': (selected == i) ? '' : null,
+ 'value': i
+ })
+ ]),
+ E('td', {}, i),
+ E('td', {'title': etitle}, renderFilterVal(i, 0)),
+ E('td', {'title': ptitle}, renderFilterVal(i, 1)),
+ E('td', {'title': ntitle}, renderFilterVal(i, 2)),
+ E('td', {'title': etitle}, renderFilterVal(i, 3)),
+ E('td', {'title': ptitle}, renderFilterVal(i, 4)),
+ E('td', {'title': ntitle}, renderFilterVal(i, 5))
+ ]));
+ };
+
+ var table = E('table', { 'class': 'lldpd-filter', 'id': this.cbid(section_id) }, [
+ E('thead', {}, [
+ E('tr', {}, [
+ E('th', { 'rowspan': 2 }),
+ E('th', { 'rowspan': 2 }, _('Filter')),
+ E('th', { 'colspan': 3 }, _('Incoming')),
+ E('th', { 'colspan': 3 }, _('Outgoing'))
+ ]),
+ E('tr', {}, [
+ E('th', {}, 'E'),
+ E('th', {}, 'P'),
+ E('th', {}, 'N'),
+ E('th', {}, 'E'),
+ E('th', {}, 'P'),
+ E('th', {}, 'N'),
+ ])
+ ]),
+ E('tbody', {}, tbody)
+ ]);
+
+ return table;
+ },
+});
+
+var CBIMultiIOSelect = form.MultiValue.extend({
+ __name__: 'CBI.MultiIOSelect',
+
+ renderWidget: function(section_id, option_index, cfgvalue) {
+ var value = (cfgvalue != null) ? cfgvalue : this.default ? this.default : '',
+ choices = this.transformChoices() ? this.transformChoices() : '';
+
+ var widget = new ui.Dropdown(L.toArray(value), choices, {
+ id: this.cbid(section_id),
+ sort: this.keylist,
+ multiple: true,
+ optional: true,
+ display_items: 5,
+ dropdown_items: -1,
+ create: true,
+ disabled: (this.readonly != null) ? this.readonly : this.map.readonly,
+ validate: L.bind(this.validate, this, section_id),
+ });
+
+ return widget.render();
+ }
+});
+
+function init() {
+ return new Promise(function(resolveFn, rejectFn) {
+ var data = session.getLocalData('luci-app-lldpd');
+ if (data !== null) {
+ return resolveFn();
+ }
+
+ data = {};
+
+ return uci.load('luci').then(function() {
+ session.setLocalData('luci-app-lldpd', data);
+ return resolveFn();
+ });
+ });
+}
+
+return L.Class.extend({
+ cbiFilterSelect: cbiFilterSelect,
+ CBIMultiIOSelect: CBIMultiIOSelect,
+ init: init,
+});
--- /dev/null
+<?xml version="1.0"?>
+<svg width="18" height="11.12" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1">
+ <metadata>image/svg+xml</metadata>
+
+ <g class="layer">
+ <title>Layer 1</title>
+ <path d="m9,11.12l9,-9l-2.12,-2.12l-6.88,6.88l-6.88,-6.88l-2.12,2.12l9,9z" fill="#ff7f00" id="svg_1"/>
+ </g>
+</svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1">
+ <metadata>image/svg+xml</metadata>
+
+ <g class="layer">
+ <title>Layer 1</title>
+ <path d="m4.58,2.83l9.17,9.17l-9.17,9.17l2.83,2.83l12,-12l-12,-12l-2.83,2.83z" fill="#ff7f00" id="svg_1"/>
+ </g>
+</svg>
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2020, Tano Systems LLC. All Rights Reserved.
+ * Copyright (c) 2023-2024. All Rights Reserved.
+ */
+
+/*
+ * Filter select widget
+ */
+table.lldpd-filter td,
+table.lldpd-filter th {
+ border: 1px solid #ccc !important;
+ padding: 2px 10px;
+ text-align: center;
+}
+
+table.lldpd-filter td,
+table.lldpd-filter td input[type="radio"] {
+ vertical-align: middle;
+}
+
+table.lldpd-filter th { font-weight: bold; }
+
+table.lldpd-filter tbody tr {
+ cursor: pointer;
+}
+
+table.lldpd-filter tr.lldpd-filter-selected td {
+ background-color: #EEE;
+}
+
+/*
+ * Parameters
+ */
+.lldpd-params {
+ column-count: 2;
+ column-gap: 24px;
+}
+
+@media only screen and (max-width: 850px) {
+ .lldpd-params {
+ column-count: 1;
+ }
+}
+
+.lldpd-params > div {
+ display: grid;
+ grid-template-columns: 1fr auto;
+ border-bottom: 1px solid #e6e6e6;
+ padding: 0 8px;
+/* column-break-inside: avoid;*/
+}
+
+.td .lldpd-params > div:last-of-type {
+ border-bottom: none;
+}
+
+.lldpd-params .lldpd-param {
+ margin-right: 10px;
+ font-weight: bold;
+}
+
+.lldpd-params .lldpd-param::after {
+ content: ':';
+}
+
+.lldpd-params .lldpd-param-value {
+ white-space: normal;
+ font-weight: normal;
+ text-align: right;
+}
+
+.td .lldpd-params {
+ column-count: 1;
+}
+
+.td .lldpd-params > div {
+ padding: 0;
+}
+
+/*
+ * Status table
+ */
+.lldpd-folded,
+.lldpd-unfolded {
+ width: 100%;
+}
+
+.lldpd-table .tr .td { cursor: pointer; }
+
+.lldpd-protocol-badge {
+ display: inline-block;
+ width: auto !important;
+ width: fit-content !important;
+ box-shadow: 0 1px 3px 0 grey;
+ padding: 0px 8px;
+ border-radius: 5px;
+ width: 100%;
+ background-color: #e6e6e6;
+ border: 0;
+ margin-right: 5px;
+ margin-bottom: 5px;
+ color: #595959;
+}
+
+.lldpd-protocol-badge.lldpd-protocol-lldp { background-color: #b7efcf; border-color: #2abd69; color: #165e34; }
+.lldpd-protocol-badge.lldpd-protocol-cdp { background-color: #b2daf3; border-color: #46a6e2; color: #1a74ac; }
+.lldpd-protocol-badge.lldpd-protocol-fdp { background-color: #f9e3b3; border-color: #b7820f; color: #b7820f; }
+.lldpd-protocol-badge.lldpd-protocol-edp { background-color: #f9e3f9; border-color: #e380e3; color: #b70f82; }
+.lldpd-protocol-badge.lldpd-protocol-sonmp { background-color: #f4ffc4; border-color: #a7ce00; color: #7e9b00; }
--- /dev/null
+/*
+ * Copyright (c) 2020 Tano Systems LLC. All Rights Reserved.
+ * Copyright (c) 2023-2024. All Rights Reserved.
+ */
+
+'use strict';
+'require rpc';
+'require form';
+'require lldpd';
+'require network';
+'require uci';
+'require tools.widgets as widgets';
+
+var callInitList = rpc.declare({
+ object: 'luci',
+ method: 'getInitList',
+ params: [ 'name' ],
+ expect: { '': {} },
+ filter: function(res) {
+ for (var k in res)
+ return +res[k].enabled;
+ return null;
+ }
+});
+
+var callInitAction = rpc.declare({
+ object: 'luci',
+ method: 'setInitAction',
+ params: [ 'name', 'action' ],
+ expect: { result: false }
+});
+
+var usage = _('See syntax <a %s>here</a>.').format('href=https://lldpd.github.io/usage.html target="_blank"');
+
+const validateioentries = function(section_id, value) {
+ if (value) {
+ const emsg = _('Cannot have both interface %s and its exclusion %s');
+ const a = value.split(' ');
+ const noex = a.filter(el=> !el.startsWith('!'));
+ const ex = a.filter(el=> el.startsWith('!') && !el.startsWith('!!'));
+ for (var i of noex) {
+ for (var e of ex) {
+ if ('!'+i == e){
+ return emsg.format(i, e);
+ }
+ }
+ }
+ }
+ return true;
+};
+
+return L.view.extend({
+ __init__: function() {
+ this.super('__init__', arguments);
+
+ // Inject CSS
+ var head = document.getElementsByTagName('head')[0];
+ var css = E('link', { 'href':
+ L.resource('lldpd/lldpd.css')
+ + '?v=#PKG_VERSION', 'rel': 'stylesheet' });
+
+ head.appendChild(css);
+ },
+
+ load: function() {
+ return Promise.all([
+ callInitList('lldpd'),
+ lldpd.init(),
+ uci.load('lldpd'),
+ network.getDevices()
+ ]);
+ },
+
+ // -----------------------------------------------------------------------------------------
+ //
+ // Basic Options
+ //
+ // -----------------------------------------------------------------------------------------
+
+ /** @private */
+ populateBasicOptions: function(s, tab, data) {
+ var o;
+ var serviceEnabled = data[0];
+ var net_devices = data[3];
+
+ // Service enable/disable
+ o = s.taboption(tab, form.Flag, 'enabled', _('Enable service'));
+ o.optional = false;
+ o.rmempty = false;
+
+ o.cfgvalue = function() {
+ return serviceEnabled ? this.enabled : this.disabled;
+ };
+
+ o.write = function(section_id, value) {
+ uci.set('lldpd', section_id, 'enabled', value);
+
+ if (value == '1') {
+ // Enable and start
+ callInitAction('lldpd', 'enable').then(function() {
+ return callInitAction('lldpd', 'start');
+ });
+ }
+ else {
+ // Stop and disable
+ callInitAction('lldpd', 'stop').then(function() {
+ return callInitAction('lldpd', 'disable');
+ });
+ }
+ };
+
+ // System description
+ o = s.taboption(tab, form.Value, 'lldp_description',
+ _('System description'),
+ _('Override %s.').format('<code>system description</code>'));
+
+ o.placeholder = 'System description';
+
+ // System hostname
+ o = s.taboption(tab, form.Value, 'lldp_hostname',
+ _('System hostname'),
+ _('Override %s.').format('<code>system hostname</code>'));
+
+ o.placeholder = 'System hostname';
+
+ /* This function returns the value for a specified key. Used to fill
+ various location fields derived from an lldpd location config string */
+ function getLocationValueFromConfString(_key) {
+ var inStr = this ? this.section.formvalue('config', 'lldp_location'):
+ uci.get('lldpd', 'config', 'lldp_location');
+ inStr = inStr ? inStr: '';
+
+ const words = inStr.trim().split(/\s+/);
+ /* This function does not assume an order to the key:value parameters.
+ Only that the value comes after its key, so optional keys can be in any order. */
+ const ix = words.indexOf(_key);
+
+ if (ix !== -1) {
+ let value = words.slice(ix + 1).join(' ');
+
+ if (value.startsWith('"')) {
+ const quoteStart = value.indexOf('"');
+ const quoteEnd = value.indexOf('"', quoteStart + 1);
+ return value.substring(quoteStart + 1, quoteEnd);
+ }
+ return _key == 'altitude' ? words[ix + 1] + ' ' + words[ix + 2] : words[ix + 1];
+ } else {
+ return ''; // Element not found
+ }
+ };
+
+ function write_lldp_location() {
+ var _input = this ? this.section.formvalue('config', '_lldp_location_type'):
+ '1';
+
+ if(_input){
+ if (_input == '1') {
+ /* location coordinate latitude
+ 48.85667N longitude 2.2014E altitude 117.47 m datum WGS84 */
+ var lat = this.section.formvalue('config', '_coordinate_lat'),
+ lon = this.section.formvalue('config', '_coordinate_lon'),
+ alt = this.section.formvalue('config', '_coordinate_alt'),
+ dat = this.section.formvalue('config', '_coordinate_dat');
+ if(lat && lon && dat) {
+ uci.set('lldpd', 'config', 'lldp_location',
+ 'coordinate latitude ' + lat +
+ ' longitude ' + lon +
+ ' altitude ' + (alt ? alt:'0 m') +
+ ' datum ' + dat );
+ }
+ }
+ else if (_input == '2') {
+ /* location address country US
+ street "Commercial Road" city "Roseville" */
+ var cc = this.section.formvalue('config', '_civic_cc'),
+ city = this.section.formvalue('config', '_civic_city'),
+ str = this.section.formvalue('config', '_civic_str'),
+ bldg = this.section.formvalue('config', '_civic_bldg'),
+ nmbr = this.section.formvalue('config', '_civic_nmbr'),
+ zip = this.section.formvalue('config', '_civic_zip');
+
+ uci.set('lldpd', 'config', 'lldp_location',
+ 'address country ' + cc.toUpperCase()
+ + (city ? ' city "' + city + '"': '')
+ + (str ? ' street "' + str + '"': '')
+ + (bldg ? ' building "' + bldg + '"': '')
+ + (nmbr ? ' number "' + nmbr + '"': '')
+ + (zip ? ' zip "' + zip + '"': ''));
+ }
+ else if (_input == '3') {
+ /* location elin 12345 */
+ var elin = this.section.formvalue('config', '_elin');
+ if(elin)
+ uci.set('lldpd', 'config', 'lldp_location', 'elin ' + elin);
+ }
+ }
+ };
+
+ // Host location
+ o = s.taboption(tab, form.ListValue, '_lldp_location_type',
+ _('Host location type'),
+ _('Override the announced location of the host.'));
+ o.value('1', _('Coordinate based'));
+ o.value('2', _('Civic address'));
+ o.value('3', _('ELIN'));
+ o.rmempty = true;
+ o.write = write_lldp_location;
+ o.load = function(section_id, value) {
+ const loc = uci.get(this.config, section_id, 'lldp_location');
+ if (!loc) return '1';
+ if (loc.toLowerCase().includes('coordinate')) {
+ return '1';
+ }
+ else if (loc.toLowerCase().includes('address country')) {
+ return '2';
+ }
+ else if (loc.toLowerCase().includes('elin')) {
+ return '3';
+ }
+ };
+
+ o = s.taboption(tab, form.Value, 'lldp_location',
+ _('Raw location config'),
+ _('Raw config string sent to lldpd, starting: [coordinate|address|elin]'));
+ o.placeholder = 'address country EU';
+ o.rmempty = true;
+ o.write = function(section_id, value) {
+ if (value) {
+ const words = value.trim().split(/\s+/),
+ regex = /^coordinate|^address|^elin/;
+ var start;
+ words.forEach(w=>{
+ if (w.match(regex)) start = w;
+ });
+ // Retain string tail from one of the regex keywords
+ return this.super('write', [ section_id,
+ value.substring(value.indexOf(start)) ]);
+ }
+ };
+ o.validate = function(section_id, value) {
+ if (value) {
+ const words = value.trim().split(/\s+/),
+ regex = /^coordinate|^address|^elin/;
+ var _eval = _("Must contain: 'coordinate ...', 'address ...' or 'elin ...'");
+ words.forEach(w=>{
+ if (w.match(regex)) _eval = true;
+ });
+ return _eval;
+ }
+ return true;
+ };
+
+ // Coordinate based
+ o = s.taboption(tab, form.Value, '_coordinate_lat',
+ _('Latitude'), '0 .. 90.000[N|S]');
+ o.depends({ '_lldp_location_type' : '1'});
+ o.datatype = "maxlength(20)";
+ o.validate = function(section_id, value) {
+ if (!value) return true;
+ var valid = _('valid syntax: 0 .. 90.000[N|S]');
+ valid = (parseFloat(value) >= 0 && parseFloat(value) <= 90) ?
+ /^-?\d+(?:\.\d+)?[NnSs]$/.test(value) ? true : valid : valid;
+ return valid;
+ }
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('latitude');
+ }
+ o.write = write_lldp_location;
+
+ o = s.taboption(tab, form.Value, '_coordinate_lon',
+ _('Longitude'), '0 .. 180.000[E|W]');
+ o.depends({ '_lldp_location_type' : '1'});
+ o.datatype = "maxlength(20)";
+ o.validate = function(section_id, value) {
+ if (!value) return true;
+ var valid = _('valid syntax: 0 .. 180.000[E|W]');
+ valid = (parseFloat(value) >= 0 && parseFloat(value) <= 180) ?
+ /^-?\d+(?:\.\d+)?[WwEe]$/.test(value) ? true : valid : valid;
+ return valid;
+ }
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('longitude');
+ }
+ o.write = write_lldp_location;
+
+ const min_alt = -100000.00,
+ max_alt = 42849672.95;
+ o = s.taboption(tab, form.Value, '_coordinate_alt',
+ _('Altitude'), '%f .. %f [m|f]'.format(min_alt, max_alt));
+ o.depends({ '_lldp_location_type' : '1'});
+ o.datatype = 'maxlength(20)';
+ o.validate = function(section_id, value) {
+ if (!value) return true;
+ var valid = _('valid syntax: %f .. %f [mf]').format(min_alt, max_alt);
+ valid = (parseFloat(value) >= min_alt && parseFloat(value) <= max_alt) ?
+ /^-?\d+(?:\.\d+)?\ [mf]$/.test(value) ? true : valid : valid;
+ return valid;
+ }
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('altitude');
+ }
+ o.write = write_lldp_location;
+
+ o = s.taboption(tab, form.ListValue, '_coordinate_dat',
+ _('Datum'));
+ o.depends({ '_lldp_location_type' : '1'});
+ o.value('WGS84');
+ o.value('NAD83');
+ o.value('NAD83/MLLW');
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('datum');
+ }
+ o.write = write_lldp_location;
+
+ // Civic address based
+ /* ISO 3166-2 CC list officially assigned + exceptional:
+ https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements */
+ o = s.taboption(tab, form.Value, '_civic_cc',
+ _('Country'), '%s'.format('<a href=%s>ISO 3166-2 CC</a>').format('https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements'));
+ o.depends({ '_lldp_location_type' : '2'});
+ o.default = 'EU';
+ o.placeholder = 'EU';
+ o.validate = function(section_id, value) {
+ if(!value) return true;
+ var valid = _('Two character CC required');
+ valid = (value.length == 2) ?
+ /^[A-Z]{2}$/i.test(value) ? true : valid : valid;
+ return valid;
+ }
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('country').toUpperCase();
+ }
+ o.write = write_lldp_location;
+
+ o = s.taboption(tab, form.Value, '_civic_city',
+ _('City'));
+ o.depends({ '_lldp_location_type' : '2'});
+ o.datatype = "maxlength(100)";
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('city');
+ }
+ o.placeholder = _('Gotham');
+ o.write = write_lldp_location;
+
+ o = s.taboption(tab, form.Value, '_civic_str',
+ _('Street'));
+ o.depends({ '_lldp_location_type' : '2'});
+ o.datatype = "maxlength(100)";
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('street');
+ }
+ o.placeholder = _('Main Street');
+ o.write = write_lldp_location;
+
+ o = s.taboption(tab, form.Value, '_civic_bldg',
+ _('Building'));
+ o.depends({ '_lldp_location_type' : '2'});
+ o.datatype = "maxlength(250)";
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('building');
+ }
+ o.placeholder = _('Empire State Bldg');
+ o.write = write_lldp_location;
+
+ o = s.taboption(tab, form.Value, '_civic_nmbr',
+ _('Number'));
+ o.depends({ '_lldp_location_type' : '2'});
+ o.datatype = "maxlength(25)";
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('number');
+ }
+ o.placeholder = _('1A');
+ o.write = write_lldp_location;
+
+ o = s.taboption(tab, form.Value, '_civic_zip',
+ _('Post-code'));
+ o.depends({ '_lldp_location_type' : '2'});
+ o.datatype = "maxlength(25)";
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('zip');
+ }
+ o.placeholder = '12345';
+ o.write = write_lldp_location;
+
+ // ELIN based
+ o = s.taboption(tab, form.Value, '_elin',
+ _('ELIN Address'));
+ o.depends({ '_lldp_location_type' : '3'});
+ o.datatype = 'and(uinteger,maxlength(25))';
+ o.load = function(section_id, value) {
+ return getLocationValueFromConfString('elin');
+ }
+ o.placeholder = '1911';
+ o.write = write_lldp_location;
+
+ // Platform
+ o = s.taboption(tab, form.Value, 'lldp_platform',
+ _('System platform description'),
+ _('Override %s.').format('<code>system platform</code>') + '<br />' +
+ _('The default description is the kernel name (Linux).'));
+
+ o.placeholder = 'System platform description';
+
+ o = s.taboption(tab, form.Flag, 'lldp_capability_advertisements', _('System capability advertisements'));
+ o.default = '1'; //lldpd internal default
+ o.rmempty = false;
+
+ // Capabilities override
+ o = s.taboption(tab, form.MultiValue, 'lldp_syscapabilities',
+ _('System capabilities'),
+ _('Override %s.').format('<code>system capabilities</code>') + '<br />' +
+ _('The default is derived from kernel information.'));
+ o.depends({lldp_capability_advertisements: '1'});
+ o.value('bridge');
+ o.value('docsis');
+ o.value('other');
+ o.value('repeater');
+ o.value('router');
+ o.value('station');
+ o.value('telephone');
+ o.value('wlan');
+ o.cfgvalue = function(section_id) {
+ return String(this.super('load', [section_id]) || this.default).split(',');
+ };
+ o.write = function(section_id, value) {
+ return this.super('write', [ section_id, L.toArray(value).join(',') ]);
+ };
+
+ o = s.taboption(tab, form.Flag, 'lldp_mgmt_addr_advertisements', _('System management IO advertisements'));
+ o.default = '1'; //lldpd internal default
+ o.rmempty = false;
+
+ // Management addresses of this system
+ // This value: lldpd.init handles as a single value, and needs a CSV for lldpd.conf: 'configure system ip management pattern'
+ o = s.taboption(tab, lldpd.CBIMultiIOSelect, 'lldp_mgmt_ip',
+ _('System management IO'),
+ _('Defaults to the first IPv4 and IPv6. ' +
+ 'If an exact IP address is provided, it is used ' +
+ 'as a management address without any check. To ' +
+ 'blacklist IPv6 addresses, use <code>!*:*</code>.') + '<br />' +
+ usage);
+ o.placeholder = 'Addresses and interfaces';
+ o.depends({lldp_mgmt_addr_advertisements: '1'});
+ o.cfgvalue = function(section_id) {
+ const opt = uci.get(this.config, section_id, this.option);
+ return opt ? opt.split(',') : '';
+ };
+ net_devices.forEach(nd => {
+ o.value(nd.getName());
+ o.value('!'+nd.getName());
+ nd.getIPAddrs().forEach(addr => o.value(addr.split('/')[0], E([], [addr.split('/')[0], ' (', E('strong', {}, nd.getName()), ')'])));
+ nd.getIP6Addrs().forEach(addr => o.value(addr.split('/')[0], E([], [addr.split('/')[0], ' (', E('strong', {}, nd.getName()), ')'])));
+ });
+ o.value('!*:*');
+ o.validate = validateioentries;
+ o.write = function(section_id, value, sep) {
+ return this.super('write', [ section_id, value.join(',') ]);
+ }
+
+ // LLDP tx interval
+ o = s.taboption(tab, form.Value, 'lldp_tx_interval',
+ _('Transmit delay'),
+ _('The delay between ' +
+ 'transmissions of LLDP PDU. The default value ' +
+ 'is 30 seconds.') + '<br />' +
+ _('Suffix %s for millisecond values.').format('<code>ms</code>'));
+ o.default = 30;
+ o.placeholder = 30;
+ o.rmempty = false;
+
+ o.validate = function(section_id, value) {
+ const pattern = /^(\d+)(?:ms)?$/;
+ if (!value.match(pattern) || parseInt(value) <= 0)
+ return _('Must be a greater than zero number optionally suffixed with "ms"');
+ return true;
+ };
+
+ // LLDP tx hold
+ o = s.taboption(tab, form.Value, 'lldp_tx_hold',
+ _('Transmit hold value'),
+ _('Determines the transmitted ' +
+ 'packet TTL (== this value * transmit delay). ' +
+ 'The default value is 4 ∴ ' +
+ 'the default TTL is 120 seconds.'));
+
+ o.datatype = 'uinteger';
+ o.default = 4;
+ o.placeholder = 4;
+ o.rmempty = false;
+
+ o.validate = function(section_id, value) {
+ if (value != parseInt(value))
+ return _('Must be a number');
+ else if (value <= 0)
+ return _('Transmit hold value must be greater than 0');
+ return true;
+ };
+
+ // Received-only mode (-r)
+ o = s.taboption(tab, form.Flag, 'readonly_mode',
+ _('Receive-only mode'),
+ _("LLDPd won't send any frames; " +
+ 'only listen to neighbors.'));
+
+ o.rmempty = false;
+ o.optional = false;
+ o.default = '0';
+ },
+
+ // -----------------------------------------------------------------------------------------
+ //
+ // Network Interfaces
+ //
+ // -----------------------------------------------------------------------------------------
+
+ /** @private */
+ populateIfacesOptions: function(s, tab, data) {
+ var o;
+ var net_devices = data[3];
+
+ // Interfaces to listen on
+ // This value: lldpd.init handles as a list value, and produces a CSV for lldpd.conf: 'configure system interface pattern'
+ o = s.taboption(tab, lldpd.CBIMultiIOSelect, 'interface',
+ _('Network IO'),
+ _('Specify which interface (not) to listen upon and send LLDPDU from. ' +
+ 'Absent any value, LLDPd uses all available physical interfaces.'));
+
+ o.value('*');
+ net_devices.forEach(nd => {
+ o.value(nd.getName());
+ o.value('!'+nd.getName());
+ o.value('!!'+nd.getName());
+ });
+ o.value('!*:*');
+ o.validate = validateioentries;
+
+ // ChassisID interfaces
+ // This value: lldpd.init handles as a list value, and produces a CSV for the -C param
+ o = s.taboption(tab, lldpd.CBIMultiIOSelect, 'cid_interface',
+ _('Network IO for chassis ID'),
+ _('Specify which interfaces (not) to use for computing chassis ID. ' +
+ 'Absent any value, all interfaces are considered. ' +
+ 'LLDPd takes the first MAC address from all the considered ' +
+ 'interfaces to compute the chassis ID.'));
+
+ o.value('*');
+ o.value('!*');
+ net_devices.forEach(nd => {
+ o.value(nd.getName());
+ o.value('!'+nd.getName());
+ o.value('!!'+nd.getName());
+ });
+ o.value('!*:*');
+ o.validate = validateioentries;
+
+ },
+
+ // -----------------------------------------------------------------------------------------
+ //
+ // Advanced Options
+ //
+ // -----------------------------------------------------------------------------------------
+
+ /** @private */
+ populateAdvancedOptions: function(s, tab, data) {
+ var o;
+
+ // SNMP agentX socket
+ /* **Note**: The init file tests for SNMP support, so agentxsocket is at worst inert. */
+ o = s.taboption(tab, form.Value, 'agentxsocket',
+ _('SNMP agentX socket path'),
+ _('When set, LLDPd enables an ' +
+ 'SNMP subagent using AgentX protocol. This enables ' +
+ 'information about other systems through SNMP.'));
+
+ o.rmempty = true;
+ o.placeholder = '/var/run/agentx.sock';
+ o.default = '';
+
+ // LLDP-MED class
+ o = s.taboption(tab, form.ListValue, 'lldp_class',
+ _('LLDP-MED device class'));
+
+ o.value('1', _('Generic Endpoint (Class I)'));
+ o.value('2', _('Media Endpoint (Class II)'));
+ o.value('3', _('Communication Device Endpoints (Class III)'));
+ o.value('4', _('Network Connectivity Device (Class IV)'));
+
+ o.default = '4';
+
+ // LLDP-MED policy
+ o = s.taboption(tab, form.Value, 'lldp_policy',
+ _('LLDP-MED policy'));
+ o.depends({lldp_class: '2'});
+ o.depends({lldp_class: '3'});
+
+ o.rmempty = true;
+ o.placeholder = 'application streaming-video';
+ o.value('application voice');
+ o.value('application voice unknown');
+ o.value('application voice-signaling');
+ o.value('application voice-signaling unknown');
+ o.value('application guest-voice');
+ o.value('application guest-voice unknown');
+ o.value('application guest-voice-signaling');
+ o.value('application guest-voice-signaling unknown');
+ o.value('application softphone-voice');
+ o.value('application softphone-voice unknown');
+ o.value('application video-conferencing');
+ o.value('application video-conferencing unknown');
+ o.value('application streaming-video');
+ o.value('application streaming-video unknown');
+ o.value('application video-signaling');
+ o.value('application video-signaling unknown');
+
+ o.validate = function(section_id, value) {
+ if (value && !value.startsWith('application '))
+ return _('Must start: application ...');
+ return true;
+ };
+
+ // LLDP-MED fast-start
+ o = s.taboption(tab, form.Flag, 'lldpmed_fast_start',
+ _('LLDP-MED fast-start'));
+
+ // LLDP-MED fast-start
+ o = s.taboption(tab, form.Value, 'lldpmed_fast_start_tx_interval',
+ _('LLDP-MED fast-start tx-interval'));
+ o.depends({lldpmed_fast_start: '1'});
+ o.datatype = 'uinteger';
+ o.placeholder = '10';
+ o.rmempty = true;
+
+ // LLDP-MED inventory TLV transmission (-i)
+ o = s.taboption(tab, form.Flag, 'lldpmed_no_inventory',
+ _('Disable LLDP-MED inventory TLV transmission'),
+ _('LLDPd will still receive (and publish using SNMP if enabled) ' +
+ 'those LLDP-MED TLV but will not send them. Use this option ' +
+ 'if you do not want to transmit sensitive information like serial numbers.'));
+
+ o.default = '0';
+
+ // Disable advertising of kernel release, version and machine. (-k)
+ o = s.taboption(tab, form.Flag, 'lldp_no_version',
+ _('Disable advertising of kernel release, version and machine'),
+ _('Kernel name (ie: Linux) will still be shared, and Inventory ' +
+ 'software version will be set to %s.').format('<code>Unknown</code>'));
+
+ o.default = '0';
+
+ // Filter neighbors (-H)
+ o = s.taboption(tab, lldpd.cbiFilterSelect, 'filter',
+ _('Specify the behaviour when detecting multiple neighbors'),
+ _('The default filter is 15. Refer to "FILTERING NEIGHBORS".') + '<br />' +
+ usage);
+
+ o.default = 15;
+
+ // Force port ID subtype
+ o = s.taboption(tab, form.ListValue, 'lldp_portidsubtype',
+ _('Force port ID subtype'),
+ _('With this option, you can force the port identifier ' +
+ 'to be the interface name or the MAC address.'));
+
+ o.value('macaddress', _('Interface MAC address'));
+ o.value('ifname', _('Interface name'));
+
+ o.default = 'macaddress';
+
+ // The destination MAC address used to send LLDPDU
+ o = s.taboption(tab, form.ListValue, 'lldp_agenttype',
+ _('LLDPDU destination MAC'),
+ _('Allows an agent ' +
+ 'to control the propagation of LLDPDUs. By default, the ' +
+ 'MAC address %s is used and limits the propagation ' +
+ 'of the LLDPDU to the nearest bridge.').format('<code>01:80:c2:00:00:0e</code>'));
+
+ o.value('nearest-bridge', '01:80:c2:00:00:0e (nearest-bridge)');
+ o.value('nearest-nontpmr-bridge', '01:80:c2:00:00:03 (nearest-nontpmr-bridge)');
+ o.value('nearest-customer-bridge', '01:80:c2:00:00:00 (nearest-customer-bridge)');
+
+ o.default = 'nearest-bridge';
+ },
+
+ // -----------------------------------------------------------------------------------------
+ //
+ // Protocols Support
+ //
+ // -----------------------------------------------------------------------------------------
+
+ /** @private */
+ populateProtocolsOptions: function(s, tab, data) {
+ var o;
+
+ o = s.taboption(tab, form.SectionValue, '_protocols', form.TypedSection, 'lldpd');
+ var ss = o.subsection;
+ ss.anonymous = true;
+ ss.addremove = false;
+
+ //
+ // LLDPD
+ // Link Layer Discovery Protocol
+ //
+ ss.tab('lldp', _('LLDP'));
+ o = ss.taboption('lldp', form.Flag, 'enable_lldp',
+ _('Enable LLDP'));
+
+ o.default = '1';
+ o.rmempty = true;
+
+ o = ss.taboption('lldp', form.Flag, 'force_lldp',
+ _('Force sending LLDP packets'),
+ _('Even when there is no LLDP peer ' +
+ 'detected but there is a peer speaking another protocol detected.') + '<br />' +
+ _('By default, LLDP packets are sent when there is a peer speaking ' +
+ 'LLDP detected or when there is no peer at all.'));
+
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable_lldp', '1');
+
+ //
+ // CDP
+ // Cisco Discovery Protocol
+ //
+ ss.tab('cdp', _('CDP'));
+ o = ss.taboption('cdp', form.Flag, 'enable_cdp',
+ _('Enable CDP'),
+ _('Enable the support of CDP protocol to deal with Cisco routers ' +
+ 'that do not speak LLDP'));
+
+ o.default = '1';
+ o.rmempty = false;
+
+ o = ss.taboption('cdp', form.ListValue, 'cdp_version',
+ _('CDP version'));
+
+ o.value('cdpv1v2', _('CDPv1 and CDPv2'));
+ o.value('cdpv2', _('Only CDPv2'));
+ o.depends('enable_cdp', '1');
+
+ o.default = 'cdpv1v2';
+
+ o = ss.taboption('cdp', form.Flag, 'force_cdp',
+ _('Send CDP packets even if no CDP peer detected'));
+
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable_cdp', '1');
+
+ o = ss.taboption('cdp', form.Flag, 'force_cdpv2',
+ _('Force sending CDPv2 packets'));
+
+ o.default = '0';
+ o.rmempty = true;
+ o.depends({
+ force_cdp: '1',
+ enable_cdp: '1',
+ cdp_version: 'cdpv1v2'
+ });
+
+ //
+ // FDP
+ // Foundry Discovery Protocol
+ //
+ ss.tab('fdp', _('FDP'));
+ o = ss.taboption('fdp', form.Flag, 'enable_fdp',
+ _('Enable FDP'),
+ _('Enable the support of FDP protocol to deal with Foundry routers ' +
+ 'that do not speak LLDP'));
+
+ o.default = '1';
+ o.rmempty = false;
+
+ o = ss.taboption('fdp', form.Flag, 'force_fdp',
+ _('Send FDP packets even if no FDP peer detected'));
+
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable_fdp', '1');
+
+ //
+ // EDP
+ // Extreme Discovery Protocol
+ //
+ ss.tab('edp', _('EDP'));
+ o = ss.taboption('edp', form.Flag, 'enable_edp',
+ _('Enable EDP'),
+ _('Enable the support of EDP protocol to deal with Extreme routers ' +
+ 'and switches that do not speak LLDP.'));
+
+ o.default = '1';
+ o.rmempty = false;
+
+ o = ss.taboption('edp', form.Flag, 'force_edp',
+ _('Send EDP packets even if no EDP peer detected'));
+
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable_edp', '1');
+
+ //
+ // SONMP
+ // SynOptics Network Management Protocol
+ //
+ // a.k.a.
+ // Nortel Topology Discovery Protocol (NTDP)
+ // Nortel Discovery Protocol (NDP)
+ // Bay Network Management Protocol (BNMP)
+ // Bay Discovery Protocol (BDP)
+ //
+ ss.tab('sonmp', _('SONMP (NTDP, NDP, BNMP, BDP)'));
+ o = ss.taboption('sonmp', form.Flag, 'enable_sonmp',
+ _('Enable SONMP'),
+ _('Enable the support of SONMP protocol to deal with Nortel ' +
+ 'routers and switches that do not speak LLDP.'));
+
+ o.default = '1';
+ o.rmempty = false;
+
+ o = ss.taboption('sonmp', form.Flag, 'force_sonmp',
+ _('Send SONMP packets even if no SONMP peer detected'));
+
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable_sonmp', '1');
+ },
+
+ /** @private */
+ populateOptions: function(s, data) {
+ var o;
+
+ s.tab('basic', _('Basic Settings'));
+ this.populateBasicOptions(s, 'basic', data);
+
+ s.tab('ifaces', _('Network Interfaces'));
+ this.populateIfacesOptions(s, 'ifaces', data);
+
+ s.tab('advanced', _('Advanced Settings'));
+ this.populateAdvancedOptions(s, 'advanced', data);
+
+ s.tab('protocols', _('Protocols Support'));
+ this.populateProtocolsOptions(s, 'protocols', data);
+ },
+
+ render: function(data) {
+ var m, s;
+
+ m = new form.Map('lldpd', _('LLDPd Settings'),
+ _('LLDPd is an implementation of IEEE 802.1ab') + ' ' +
+ '(<abbr title="Link Layer Discovery Protocol">LLDP</abbr>).' + ' ' +
+ _('On this page you may configure LLDPd parameters.'));
+
+ s = m.section(form.TypedSection, 'lldpd');
+ s.addremove = false;
+ s.anonymous = true;
+
+ this.populateOptions(s, data);
+
+ return m.render();
+ },
+});
--- /dev/null
+/*
+ * Copyright (c) 2020 Tano Systems. All Rights Reserved.
+ * Copyright (c) 2023-2024. All Rights Reserved.
+ */
+
+'use strict';
+'require rpc';
+'require form';
+'require lldpd';
+'require dom';
+'require poll';
+
+var callLLDPStatus = rpc.declare({
+ object: 'luci.lldpd',
+ method: 'getStatus',
+ expect: {}
+});
+
+var dataMap = {
+ local: {
+ localChassis: null,
+ },
+ remote: {
+ neighbors: null,
+ statistics: null,
+ },
+};
+
+return L.view.extend({
+ __init__: function() {
+ this.super('__init__', arguments);
+
+ this.rowsUnfolded = {};
+
+ this.tableNeighbors = E('div', { 'class': 'table lldpd-table' }, [
+ E('div', { 'class': 'tr table-titles' }, [
+ E('div', { 'class': 'th left top' }, _('Local interface')),
+ E('div', { 'class': 'th left top' }, _('Protocol')),
+ E('div', { 'class': 'th left top' }, _('Discovered chassis')),
+ E('div', { 'class': 'th left top' }, _('Discovered port')),
+ ]),
+ E('div', { 'class': 'tr center placeholder' }, [
+ E('div', { 'class': 'td' }, E('em', { 'class': 'spinning' },
+ _('Collecting data...'))),
+ ])
+ ]);
+
+ this.tableStatistics = E('div', { 'class': 'table lldpd-table' }, [
+ E('div', { 'class': 'tr table-titles' }, [
+ E('div', { 'class': 'th left top' }, _('Local interface')),
+ E('div', { 'class': 'th left top' }, _('Protocol')),
+ E('div', { 'class': 'th left top' }, _('Administrative Status')),
+ E('div', { 'class': 'th right top' }, _('Tx')),
+ E('div', { 'class': 'th right top' }, _('Rx')),
+ E('div', { 'class': 'th right top' }, _('Tx discarded')),
+ E('div', { 'class': 'th right top' }, _('Rx unrecognized')),
+ E('div', { 'class': 'th right top' }, _('Ageout count')),
+ E('div', { 'class': 'th right top' }, _('Insert count')),
+ E('div', { 'class': 'th right top' }, _('Delete count')),
+ ]),
+ E('div', { 'class': 'tr center placeholder' }, [
+ E('div', { 'class': 'td' }, E('em', { 'class': 'spinning' },
+ _('Collecting data...'))),
+ ])
+ ]);
+
+ // Inject CSS
+ var head = document.getElementsByTagName('head')[0];
+ var css = E('link', { 'href':
+ L.resource('lldpd/lldpd.css')
+ + '?v=#PKG_VERSION', 'rel': 'stylesheet' });
+
+ head.appendChild(css);
+ },
+
+ load: function() {
+ return Promise.all([
+ L.resolveDefault(callLLDPStatus(), {}),
+ lldpd.init(),
+ ]);
+ },
+
+ /** @private */
+ renderParam: function(param, value) {
+ if (typeof value === 'undefined')
+ return '';
+
+ return E('div', {}, [
+ E('span', { 'class': 'lldpd-param' }, param),
+ E('span', { 'class': 'lldpd-param-value' }, value)
+ ]);
+ },
+
+ /** @private */
+ renderAge: function(v) {
+ if (typeof v === 'undefined')
+ return "–";
+
+ return E('nobr', {}, v);
+ },
+
+ /** @private */
+ renderIdType: function(v) {
+ if (typeof v === 'undefined')
+ return "–";
+
+ if (v == 'mac')
+ return _('MAC address');
+ else if (v == 'ifname')
+ return _('Interface name');
+ else if (v == 'local')
+ return _('Local ID');
+ else if (v == 'ip')
+ return _('IP address');
+
+ return v;
+ },
+
+ /** @private */
+ renderProtocol: function(v) {
+ if (typeof v === 'undefined' || v == 'unknown')
+ return "–";
+
+ if (v == 'LLDP')
+ return E('span', { 'class': 'lldpd-protocol-badge lldpd-protocol-lldp' }, v);
+ else if ((v == 'CDPv1') || (v == 'CDPv2'))
+ return E('span', { 'class': 'lldpd-protocol-badge lldpd-protocol-cdp' }, v);
+ else if (v == 'FDP')
+ return E('span', { 'class': 'lldpd-protocol-badge lldpd-protocol-fdp' }, v);
+ else if (v == 'EDP')
+ return E('span', { 'class': 'lldpd-protocol-badge lldpd-protocol-edp' }, v);
+ else if (v == 'SONMP')
+ return E('span', { 'class': 'lldpd-protocol-badge lldpd-protocol-sonmp' }, v);
+ else
+ return E('span', { 'class': 'lldpd-protocol-badge' }, v);
+ },
+
+ /** @private */
+ renderAdminStatus: function(status) {
+ if ((typeof status === 'undefined') || !Array.isArray(status))
+ return '–';
+
+ if (status[0].value === 'RX and TX')
+ return _('Rx and Tx');
+ else if (status[0].value === 'RX only')
+ return _('Rx only');
+ else if (status[0].value === 'TX only')
+ return _('Tx only');
+ else if (status[0].value === 'disabled')
+ return _('Disabled');
+ else
+ return _('Unknown');
+ },
+
+ /** @private */
+ renderNumber: function(v) {
+ if (parseInt(v))
+ return v;
+
+ return '–';
+ },
+
+ /** @private */
+ renderPort: function(port) {
+ if (typeof port.port !== 'undefined')
+ {
+ if (typeof port.port[0].descr !== 'undefined' &&
+ typeof port.port[0].id[0].value !== 'undefined' &&
+ port.port[0].descr[0].value !== port.port[0].id[0].value)
+ {
+ return [
+ E('strong', {}, port.port[0].descr[0].value),
+ E('br', {}),
+ port.port[0].id[0].value
+ ];
+ }
+ else
+ {
+ if (typeof port.port[0].descr !== 'undefined')
+ return port.port[0].descr[0].value;
+ else
+ return port.port[0].id[0].value;
+ }
+ }
+ else
+ {
+ return '%s'.format(port.name);
+ }
+ },
+
+ /** @private */
+ renderPortParamTableShort: function(port) {
+ var items = [];
+
+ items.push(this.renderParam(_('Name'), port.name));
+ items.push(this.renderParam(_('Age'), this.renderAge(port.age)));
+
+ return E('div', { 'class': 'lldpd-params' }, items);
+ },
+
+ /** @private */
+ renderPortParamTable: function(port, only_id_and_ttl) {
+ var items = [];
+
+ if (!only_id_and_ttl) {
+ items.push(this.renderParam(_('Name'), port.name));
+ items.push(this.renderParam(_('Age'), this.renderAge(port.age)));
+ }
+
+ if (typeof port.port !== 'undefined')
+ {
+ if (typeof port.port[0].id !== 'undefined')
+ {
+ items.push(this.renderParam(_('Port ID'),
+ port.port[0].id[0].value));
+
+ items.push(this.renderParam(_('Port ID type'),
+ this.renderIdType(port.port[0].id[0].type)));
+ }
+
+ if (typeof port.port[0].descr !== 'undefined')
+ items.push(this.renderParam(_('Port description'),
+ port.port[0].descr[0].value));
+
+ if (typeof port.ttl !== 'undefined')
+ items.push(this.renderParam(_('TTL'), port.ttl[0].ttl));
+ else if (port.port[0].ttl !== 'undefined')
+ items.push(this.renderParam(_('TTL'), port.port[0].ttl[0].value));
+
+ if (typeof port.port[0].mfs !== 'undefined')
+ items.push(this.renderParam(_('MFS'), port.port[0].mfs[0].value));
+ }
+
+ return E('div', { 'class': 'lldpd-params' }, items);
+ },
+
+ /** @private */
+ renderChassis: function(ch) {
+ if (typeof ch.name !== 'undefined' &&
+ typeof ch.descr !== 'undefined' &&
+ typeof ch.name[0].value !== 'undefined' &&
+ typeof ch.descr[0].value !== 'undefined')
+ {
+ return [
+ E('strong', {}, ch.name[0].value),
+ E('br', {}),
+ ch.descr[0].value
+ ];
+ }
+ else if (typeof ch.name !== 'undefined' &&
+ typeof ch.name[0].value !== 'undefined')
+ return E('strong', {}, ch.name[0].value);
+ else if (typeof ch.descr !== 'undefined' &&
+ typeof ch.descr[0].value !== 'undefined')
+ return ch.descr[0].value;
+ else if (typeof ch.id !== 'undefined' &&
+ typeof ch.id[0].value !== 'undefined')
+ return ch.id[0].value;
+ else
+ return _('Unknown');
+ },
+
+ /** @private */
+ renderChassisParamTable: function(ch) {
+ var items = [];
+
+ if (typeof ch.name !== 'undefined')
+ items.push(this.renderParam(_('Name'), ch.name[0].value));
+
+ if (typeof ch.descr !== 'undefined')
+ items.push(this.renderParam(_('Description'), ch.descr[0].value));
+
+ if (typeof ch.id !== 'undefined') {
+ items.push(this.renderParam(_('ID'), ch.id[0].value));
+ items.push(this.renderParam(_('ID type'),
+ this.renderIdType(ch.id[0].type)));
+ }
+
+ // Management addresses
+ if (typeof ch['mgmt-ip'] !== 'undefined') {
+ var ips = '';
+
+ if (ch['mgmt-ip'].length > 0) {
+ // Array of addresses
+ for (var ip = 0; ip < ch["mgmt-ip"].length; ip++)
+ ips += ch['mgmt-ip'][ip].value + '<br />';
+ }
+ else {
+ // One address
+ ips += ch['mgmt-ip'][0].value;
+ }
+
+ items.push(this.renderParam(_('Management IP(s)'), ips));
+ }
+
+ if (typeof ch.capability !== 'undefined') {
+ var caps = '';
+
+ if (ch.capability.length > 0)
+ {
+ // Array of capabilities
+ for (var cap = 0; cap < ch.capability.length; cap++) {
+ caps += ch.capability[cap].type;
+ caps += ' (' + (ch.capability[cap].enabled
+ ? _('enabled') : _('disabled')) + ')';
+ caps += '<br />';
+ }
+ }
+ else
+ {
+ // One capability
+ caps += ch.capability[0].type;
+ caps += ' (' + (ch.capability[0].enabled
+ ? _('enabled') : _('disabled')) + ')';
+ }
+
+ items.push(this.renderParam(_('Capabilities'), caps));
+ }
+
+ return E('div', { 'class': 'lldpd-params' }, items);
+ },
+
+ /** @private */
+ getFoldingImage: function(unfolded) {
+ return L.resource('lldpd/details_' +
+ (unfolded ? 'hide' : 'show') + '.svg');
+ },
+
+ /** @private */
+ generateRowId: function(str) {
+ return str.replace(/[^a-z0-9]/gi, '-');
+ },
+
+ /** @private */
+ handleToggleFoldingRow: function(row, row_id) {
+ var e_img = row.querySelector('img');
+ var e_folded = row.querySelectorAll('.lldpd-folded');
+ var e_unfolded = row.querySelectorAll('.lldpd-unfolded');
+
+ if (e_folded.length != e_unfolded.length)
+ return;
+
+ var do_unfold = (e_folded[0].style.display !== 'none');
+ this.rowsUnfolded[row_id] = do_unfold;
+
+ for (var i = 0; i < e_folded.length; i++)
+ {
+ if (do_unfold)
+ {
+ e_folded[i].style.display = 'none';
+ e_unfolded[i].style.display = 'block';
+ }
+ else
+ {
+ e_folded[i].style.display = 'block';
+ e_unfolded[i].style.display = 'none';
+ }
+ }
+
+ e_img.src = this.getFoldingImage(do_unfold);
+ },
+
+ /** @private */
+ makeFoldingTableRow: function(row, unfolded) {
+ //
+ // row[0] - row id
+ // row[1] - contents for first cell in row
+ // row[2] - contents for second cell in row
+ // ...
+ // row[N] - contents for N-th cell in row
+ //
+ if (row.length < 2)
+ return row;
+
+ for (let i = 1; i < row.length; i++) {
+ if (i == 1) {
+ // Fold/unfold image appears only in first column
+ var dImg = E('div', { 'style': 'padding: 0 8px 0 0;' }, [
+ E('img', { 'width': '16px', 'src': this.getFoldingImage(unfolded) }),
+ ]);
+ }
+
+ if (Array.isArray(row[i])) {
+ // row[i][0] = folded contents
+ // row[i][1] = unfolded contents
+
+ // Folded cell data
+ let dFolded = E('div', {
+ 'class': 'lldpd-folded',
+ 'style': unfolded ? 'display: none;' : 'display: block;'
+ }, row[i][0]);
+
+ // Unfolded cell data
+ let dUnfolded = E('div', {
+ 'class': 'lldpd-unfolded',
+ 'style': unfolded ? 'display: block;' : 'display: none;'
+ }, row[i][1]);
+
+ if (i == 1) {
+ row[i] = E('div', {
+ 'style': 'display: flex; flex-wrap: nowrap;'
+ }, [ dImg, dFolded, dUnfolded ]);
+ }
+ else {
+ row[i] = E('div', {}, [ dFolded, dUnfolded ]);
+ }
+ }
+ else {
+ // row[i] = same content for folded and unfolded states
+
+ if (i == 1) {
+ row[i] = E('div', {
+ 'style': 'display: flex; flex-wrap: nowrap;'
+ }, [ dImg, E('div', row[i]) ]);
+ }
+ }
+ }
+
+ return row;
+ },
+
+ /** @private */
+ makeNeighborsTableRow: function(obj) {
+ if (typeof obj === 'undefined')
+ obj.name = 'Unknown';
+
+ var new_id = obj.name + '-' + obj.rid;
+
+ if (typeof obj.port !== 'undefined') {
+ if (typeof obj.port[0].id !== 'undefined')
+ new_id += "-" + obj.port[0].id[0].value;
+
+ if (typeof obj.port[0].descr !== 'undefined')
+ new_id += "-" + obj.port[0].descr[0].value;
+ }
+
+ var row_id = this.generateRowId(new_id);
+
+ return this.makeFoldingTableRow([
+ row_id,
+ [
+ '%s'.format(obj.name),
+ this.renderPortParamTableShort(obj)
+ ],
+ this.renderProtocol(obj.via),
+ [
+ this.renderChassis(obj.chassis[0]),
+ this.renderChassisParamTable(obj.chassis[0])
+ ],
+ [
+ this.renderPort(obj),
+ this.renderPortParamTable(obj, true)
+ ]
+ ], this.rowsUnfolded[row_id] || false);
+ },
+
+ /** @private */
+ renderInterfaceProtocols: function(iface, neighbors) {
+ if ((typeof iface === 'undefined') ||
+ (typeof neighbors == 'undefined') ||
+ (typeof neighbors.lldp[0] === 'undefined') ||
+ (typeof neighbors.lldp[0].interface === 'undefined'))
+ return "–";
+
+ var name = iface.name;
+ var protocols = [];
+
+ /* Search protocols for interface <name> */
+ neighbors.lldp[0].interface.forEach(function(n) {
+ if (n.name !== name)
+ return;
+
+ protocols.push(this.renderProtocol(n.via));
+ }.bind(this));
+
+ if (protocols.length > 0)
+ return E('span', {}, protocols);
+ else
+ return "–";
+ },
+
+ /** @private */
+ makeStatisticsTableRow: function(sobj, iobj, neighbors) {
+ var row_id = this.generateRowId(iobj.name);
+
+ return this.makeFoldingTableRow([
+ row_id,
+ [
+ this.renderPort(iobj), // folded
+ this.renderPortParamTable(iobj, false) // unfolded
+ ],
+ this.renderInterfaceProtocols(iobj, neighbors),
+ this.renderAdminStatus(iobj.status),
+ this.renderNumber(sobj.tx[0].tx),
+ this.renderNumber(sobj.rx[0].rx),
+ this.renderNumber(sobj.rx_discarded_cnt[0].rx_discarded_cnt),
+ this.renderNumber(sobj.rx_unrecognized_cnt[0].rx_unrecognized_cnt),
+ this.renderNumber(sobj.ageout_cnt[0].ageout_cnt),
+ this.renderNumber(sobj.insert_cnt[0].insert_cnt),
+ this.renderNumber(sobj.delete_cnt[0].delete_cnt)
+ ], this.rowsUnfolded[row_id] || false);
+ },
+
+ /** @private */
+ updateTable: function(table, data, placeholder) {
+ var target = isElem(table) ? table : document.querySelector(table);
+
+ if (!isElem(target))
+ return;
+
+ target.querySelectorAll(
+ '.tr.table-titles, .cbi-section-table-titles').forEach(L.bind(function(thead) {
+ var titles = [];
+
+ thead.querySelectorAll('.th').forEach(function(th) {
+ titles.push(th);
+ });
+
+ if (Array.isArray(data)) {
+ var n = 0, rows = target.querySelectorAll('.tr');
+
+ data.forEach(L.bind(function(row) {
+ var id = row[0];
+ var trow = E('div', { 'class': 'tr', 'click': L.bind(function(ev) {
+ this.handleToggleFoldingRow(ev.currentTarget, id);
+ // lldpd_folding_toggle(ev.currentTarget, id);
+ }, this) });
+
+ for (var i = 0; i < titles.length; i++) {
+ var text = (titles[i].innerText || '').trim();
+ var td = trow.appendChild(E('div', {
+ 'class': titles[i].className,
+ 'data-title': (text !== '') ? text : null
+ }, row[i + 1] || ''));
+
+ td.classList.remove('th');
+ td.classList.add('td');
+ }
+
+ trow.classList.add('cbi-rowstyle-%d'.format((n++ % 2) ? 2 : 1));
+
+ if (rows[n])
+ target.replaceChild(trow, rows[n]);
+ else
+ target.appendChild(trow);
+ }, this));
+
+ while (rows[++n])
+ target.removeChild(rows[n]);
+
+ if (placeholder && target.firstElementChild === target.lastElementChild) {
+ var trow = target.appendChild(
+ E('div', { 'class': 'tr placeholder' }));
+
+ var td = trow.appendChild(
+ E('div', { 'class': 'center ' + titles[0].className }, placeholder));
+
+ td.classList.remove('th');
+ td.classList.add('td');
+ }
+ } else {
+ thead.parentNode.style.display = 'none';
+
+ thead.parentNode.querySelectorAll('.tr, .cbi-section-table-row').forEach(function(trow) {
+ if (trow !== thead) {
+ var n = 0;
+ trow.querySelectorAll('.th, .td').forEach(function(td) {
+ if (n < titles.length) {
+ var text = (titles[n++].innerText || '').trim();
+ if (text !== '')
+ td.setAttribute('data-title', text);
+ }
+ });
+ }
+ });
+
+ thead.parentNode.style.display = '';
+ }
+ }, this));
+ },
+
+ /** @private */
+ startPolling: function() {
+ poll.add(L.bind(function() {
+ return callLLDPStatus().then(L.bind(function(data) {
+ this.renderData(data);
+ }, this));
+ }, this));
+ },
+
+ /** @private */
+ renderDataLocalChassis: function(data) {
+ if (data &&
+ typeof data !== 'undefined' &&
+ typeof data['local-chassis'] !== 'undefined' &&
+ typeof data['local-chassis'][0].chassis[0].name !== 'undefined') {
+ return this.renderChassisParamTable(data['local-chassis'][0].chassis[0]);
+ }
+ else {
+ return E('div', { 'class': 'alert-message warning' },
+ _('No data to display'));
+ }
+ },
+
+ /** @private */
+ renderDataNeighbors: function(neighbors) {
+ var rows = [];
+
+ if (neighbors &&
+ typeof neighbors !== 'undefined' &&
+ typeof neighbors.lldp !== 'undefined')
+ {
+ var ifaces = neighbors.lldp[0].interface;
+
+ // Fill table rows
+ if (typeof ifaces !== 'undefined') {
+ for (i = 0; i < ifaces.length; i++)
+ rows.push(this.makeNeighborsTableRow(ifaces[i]));
+ }
+ }
+
+ return rows;
+ },
+
+ /** @private */
+ renderDataStatistics: function(statistics, interfaces, neighbors) {
+ var rows = [];
+
+ if (statistics &&
+ interfaces &&
+ typeof statistics !== 'undefined' &&
+ typeof interfaces !== 'undefined' &&
+ typeof statistics.lldp !== 'undefined' &&
+ typeof interfaces.lldp !== 'undefined')
+ {
+ var sifaces = statistics.lldp[0].interface;
+ var ifaces = interfaces.lldp[0].interface;
+
+ if ((typeof sifaces !== 'undefined') &&
+ (typeof ifaces !== 'undefined')) {
+ for (var i = 0; i < sifaces.length; i++)
+ rows.push(this.makeStatisticsTableRow(sifaces[i], ifaces[i], neighbors));
+ }
+ }
+
+ return rows;
+ },
+
+ /** @private */
+ renderData: function(data) {
+ var r;
+
+ r = this.renderDataLocalChassis(data.chassis);
+ dom.content(document.getElementById('lldpd-local-chassis'), r);
+
+ r = this.renderDataNeighbors(data.neighbors);
+ this.updateTable(this.tableNeighbors, r,
+ _('No data to display'));
+
+ r = this.renderDataStatistics(data.statistics, data.interfaces, data.neighbors);
+ this.updateTable(this.tableStatistics, r,
+ _('No data to display'));
+ },
+
+ render: function(data) {
+ var m, s, ss, o;
+
+ m = new form.JSONMap(dataMap,
+ _('LLDP Status'),
+ _('This page allows you to see discovered LLDP neighbors, ' +
+ 'local interfaces statistics and local chassis information.'));
+
+ s = m.section(form.NamedSection, 'local', 'local',
+ _('Local Chassis'));
+
+ o = s.option(form.DummyValue, 'localChassis');
+ o.render = function() {
+ return E('div', { 'id': 'lldpd-local-chassis' }, [
+ E('em', { 'class': 'spinning' }, _('Collecting data...'))
+ ]);
+ };
+
+ s = m.section(form.NamedSection, 'remote', 'remote');
+
+ s.tab('neighbors', _('Discovered Neighbors'));
+ s.tab('statistics', _('Interface Statistics'));
+
+ o = s.taboption('neighbors', form.DummyValue, 'neighbors');
+ o.render = L.bind(function() {
+ return E('div', { 'class': 'table-wrapper' }, [
+ this.tableNeighbors
+ ]);
+ }, this);
+
+ o = s.taboption('statistics', form.DummyValue, 'statistics');
+ o.render = L.bind(function() {
+ return E('div', { 'class': 'table-wrapper' }, [
+ this.tableStatistics
+ ]);
+ }, this);
+
+ return m.render().then(L.bind(function(rendered) {
+ this.startPolling();
+ return rendered;
+ }, this));
+ },
+
+ handleSaveApply: null,
+ handleSave: null,
+ handleReset: null
+});
--- /dev/null
+msgid ""
+msgstr ""
+"Project-Id-Version: luci-app-lldpd\n"
+"PO-Revision-Date: 2021-04-06 15:55+0300\n"
+"Language-Team: Tano Systems LLC\n"
+"Language: ru\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n"
+"%100<10 || n%100>=20) ? 1 : 2);\n"
+"POT-Creation-Date: 2018-05-23 18:25+0300\n"
+"X-Generator: Poedit 2.3\n"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:54
+msgid "Administrative Status"
+msgstr "Административное состояние"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:588
+msgid "Advanced Settings"
+msgstr "Дополнительные настройки"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:198
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:209
+msgid "Age"
+msgstr "Возраст"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:59
+msgid "Ageout count"
+msgstr "Устарело"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:422
+msgid ""
+"Allows an agent to control the propagation of LLDPDUs. By default, the MAC "
+"address %s is used and limits the propagation of the LLDPDU to the nearest "
+"bridge."
+msgstr ""
+"Данный параметр позволяет агенту контролировать распространение LLDPDU. По "
+"умолчанию используется MAC-адрес %s и ограничивает распространение LLDPDU до "
+"ближайшего моста."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:582
+msgid "Basic Settings"
+msgstr "Основные настройки"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:464
+msgid ""
+"By default, LLDP packets are sent when there is a peer speaking LLDP "
+"detected or when there is no peer at all."
+msgstr ""
+"По умолчанию пакеты LLDP отправляются, когда обнаружен сосед с поддержкой "
+"LLDP или когда вообще нет обнаруженных соседей."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:475
+msgid "CDP"
+msgstr "CDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:485
+msgid "CDP version"
+msgstr "Версия протокола CDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:487
+msgid "CDPv1 and CDPv2"
+msgstr "CDPv1 и CDPv2"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:39
+msgid "Cannot have both interface %s and its exclusion %s"
+msgstr "Оба и интерфейс %s и его исключение %s нельзя"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:319
+msgid "Capabilities"
+msgstr "Возможности"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:46
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:65
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:681
+msgid "Collecting data..."
+msgstr "Сбор данных..."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:335
+msgid "Communication Device Endpoints (Class III)"
+msgstr "Communication Device Endpoints (класс III)"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:186
+msgid ""
+"Defaults to the first IPv4 and IPv6. If an exact IP address is provided, it "
+"is used as a management address without any check. To blacklist IPv6 "
+"addresses, use <code>!*:*</code>."
+msgstr ""
+"Если не указано, используется первый IPv4 и первый IPv6 адреса. Если указан "
+"конкретный IP-адрес, он будет использован как адрес управления без какой-"
+"либо проверки. Если вы хотите занести в черный список IPv6-адреса, вы можете "
+"использовать шаблон <code>!*:*</code>."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:61
+msgid "Delete count"
+msgstr "Удалено"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:273
+msgid "Description"
+msgstr "Описание"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:230
+msgid ""
+"Determines the transmitted packet TTL (== this value * transmit delay). The "
+"default value is 4 ∴ the default TTL is 120 seconds."
+msgstr ""
+"Это значение используется для вычисления TTL переданных пакетов, которое "
+"является произведением этого значения и задержки передачи. Значение по "
+"умолчанию равно 4. Соответственно, значение TTL по умолчанию составляет 120 "
+"секунд."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:385
+msgid "Disable LLDP-MED inventory TLV transmission"
+msgstr "Отключить отправку инвентарной информации LLDP-MED TLV"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:394
+msgid "Disable advertising of kernel release, version and machine"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:152
+msgid "Disabled"
+msgstr "Отключено"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:687
+msgid "Discovered Neighbors"
+msgstr "Обнаруженные соседи"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:41
+msgid "Discovered chassis"
+msgstr "Обнаруженное шасси"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:42
+msgid "Discovered port"
+msgstr "Обнаруженный порт"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:535
+msgid "EDP"
+msgstr "EDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:477
+msgid "Enable CDP"
+msgstr "Включить CDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:537
+msgid "Enable EDP"
+msgstr "Включить EDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:517
+msgid "Enable FDP"
+msgstr "Включить FDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:455
+msgid "Enable LLDP"
+msgstr "Включить LLDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:563
+msgid "Enable SONMP"
+msgstr "Включить SONMP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:89
+msgid "Enable service"
+msgstr "Включить службу"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:478
+msgid ""
+"Enable the support of CDP protocol to deal with Cisco routers that do not "
+"speak LLDP"
+msgstr ""
+"Включить поддержку протокола CDP для работы с маршрутизаторами Cisco, "
+"которые не имеют поддержки LLDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:538
+msgid ""
+"Enable the support of EDP protocol to deal with Extreme routers and switches "
+"that do not speak LLDP."
+msgstr ""
+"Включить поддержку протокола EDP для работы с маршрутизаторами и "
+"коммутаторам Extreme, которые не имеют поддержки LLDP."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:518
+msgid ""
+"Enable the support of FDP protocol to deal with Foundry routers that do not "
+"speak LLDP"
+msgstr ""
+"Включить поддержку протокола FDP для работы с маршрутизаторами Foundry, "
+"которые не имеют поддержки LLDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:564
+msgid ""
+"Enable the support of SONMP protocol to deal with Nortel routers and "
+"switches that do not speak LLDP."
+msgstr ""
+"Включить поддержку протокола SONMP для работы с маршрутизаторами и "
+"коммутаторами Nortel, которые не имеют поддержки LLDP."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:462
+msgid ""
+"Even when there is no LLDP peer detected but there is a peer speaking "
+"another protocol detected."
+msgstr ""
+"Даже если соседей с поддержкой LLDP не обнаружено, но есть соседи, с "
+"поддержкой другого протокола."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:515
+msgid "FDP"
+msgstr "FDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:162
+msgid "Filter"
+msgstr "Фильтр"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:410
+msgid "Force port ID subtype"
+msgstr "Использовать в качестве ID порта"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:501
+msgid "Force sending CDPv2 packets"
+msgstr "Форсировать отправку CDPv2 пакетов"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:461
+msgid "Force sending LLDP packets"
+msgstr "Форсировать отправку LLDP пакетов"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:333
+msgid "Generic Endpoint (Class I)"
+msgstr "Generic Endpoint (класс I)"
+
+#: applications/luci-app-lldpd/root/usr/share/rpcd/acl.d/luci-app-lldpd.json:18
+msgid "Grant access for LLDP configuration"
+msgstr "Предоставить доступ к конфигурации LLDP"
+
+#: applications/luci-app-lldpd/root/usr/share/rpcd/acl.d/luci-app-lldpd.json:3
+msgid "Grant access for LLDP status information"
+msgstr "Предоставить доступ к информации о состоянии LLDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:130
+msgid "Host location"
+msgstr "Местоположение хоста"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:276
+msgid "ID"
+msgstr "ID"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:277
+msgid "ID type"
+msgstr "Тип ID"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:116
+msgid "IP address"
+msgstr "IP-адрес"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:163
+msgid "Incoming"
+msgstr "Входящие"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:60
+msgid "Insert count"
+msgstr "Обнаружено"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:414
+msgid "Interface MAC address"
+msgstr "MAC-адрес интерфейса"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:688
+msgid "Interface Statistics"
+msgstr "Статистика интерфейсов"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:415
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:112
+msgid "Interface name"
+msgstr "Имя интерфейса"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:395
+msgid ""
+"Kernel name (ie: Linux) will still be shared, and Inventory software version "
+"will be set to %s."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:453
+#: applications/luci-app-lldpd/root/usr/share/luci/menu.d/luci-app-lldpd.json:3
+msgid "LLDP"
+msgstr "LLDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:671
+msgid "LLDP Status"
+msgstr "Состояние LLDP"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:331
+msgid "LLDP-MED device class"
+msgstr "Класс устройства LLDP-MED"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:373
+msgid "LLDP-MED fast-start"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:377
+msgid "LLDP-MED fast-start tx-interval"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:342
+msgid "LLDP-MED policy"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:421
+msgid "LLDPDU destination MAC"
+msgstr "MAC-адрес назначения, используемый для отправки LLDPDU."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:598
+msgid "LLDPd Settings"
+msgstr "Настройки LLDPd"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:599
+msgid "LLDPd is an implementation of IEEE 802.1ab"
+msgstr "LLDPd это программная реализация стандарта IEEE 802.1ab"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:386
+msgid ""
+"LLDPd will still receive (and publish using SNMP if enabled) those LLDP-MED "
+"TLV but will not send them. Use this option if you do not want to transmit "
+"sensitive information like serial numbers."
+msgstr ""
+"LLDPd будет по прежнему получать (и публиковать, используя SNMP, если он "
+"включен) информацию LLDP-MED TLV, но не будет отправлять. Используйте эту "
+"опцию, если вы не хотите передавать важную информацию, такую как серийные "
+"номера."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:251
+msgid "LLDPd won't send any frames; only listen to neighbors."
+msgstr ""
+"С этой опцией LLDPd не будет отправлять какие-либо пакеты. LLDPd будет "
+"только прослушивать сеть для обнаружения соседей."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:676
+msgid "Local Chassis"
+msgstr "Локальное шасси"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:114
+msgid "Local ID"
+msgstr "Локально заданный ID"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:39
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:52
+msgid "Local interface"
+msgstr "Локальный интерфейс"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:110
+msgid "MAC address"
+msgstr "MAC-адрес"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:233
+msgid "MFS"
+msgstr "MFS"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:295
+msgid "Management IP(s)"
+msgstr "IP-адреса"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:334
+msgid "Media Endpoint (Class II)"
+msgstr "Media Endpoint (класс II)"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:223
+msgid "Must be a greater than zero number optionally suffixed with \"ms\""
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:242
+msgid "Must be a number"
+msgstr "Должно быть числом"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:139
+msgid "Must start: 'coordinate ...', 'address ...' or 'elin ...'"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:367
+msgid "Must start: application ..."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:197
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:208
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:270
+msgid "Name"
+msgstr "Имя"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:336
+msgid "Network Connectivity Device (Class IV)"
+msgstr "Network Connectivity Device (класс IV)"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:273
+msgid "Network IO"
+msgstr "Сетевые интерфейсы"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:289
+msgid "Network IO for chassis ID"
+msgstr "Сетевые интерфейсы, используемые для вычисления ID шасси (chassis ID)"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:585
+msgid "Network Interfaces"
+msgstr "Сетевые интерфейсы"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:603
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:660
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:664
+msgid "No data to display"
+msgstr "Нет данных для отображения"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:601
+msgid "On this page you may configure LLDPd parameters."
+msgstr "На данной странице можно настроить параметры LLDPd."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:488
+msgid "Only CDPv2"
+msgstr "Только CDPv2"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:164
+msgid "Outgoing"
+msgstr "Исходящие"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:117
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:124
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:148
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:160
+msgid "Override %s."
+msgstr "Переопределить %s."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:131
+msgid "Override the announced location of the host."
+msgstr "Переопределите объявленное местоположение хоста."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:216
+msgid "Port ID"
+msgstr "ID порта"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:219
+msgid "Port ID type"
+msgstr "Тип ID порта"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:224
+msgid "Port description"
+msgstr "Описание порта"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:40
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:53
+msgid "Protocol"
+msgstr "Протокол"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:591
+msgid "Protocols Support"
+msgstr "Поддержка протоколов"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:250
+msgid "Receive-only mode"
+msgstr "Режим «только приём»"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:56
+msgid "Rx"
+msgstr "Rx"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:146
+msgid "Rx and Tx"
+msgstr "Rx и Tx"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:148
+msgid "Rx only"
+msgstr "Только Rx"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:58
+msgid "Rx unrecognized"
+msgstr "Rx (не распознано)"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:561
+msgid "SONMP (NTDP, NDP, BNMP, BDP)"
+msgstr "SONMP (NTDP, NDP, BNMP, BDP)"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:35
+msgid "See syntax <a %s>here</a>."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:494
+msgid "Send CDP packets even if no CDP peer detected"
+msgstr "Отправлять CDP пакеты даже если не обнаружено соседей с CDP протоколом"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:545
+msgid "Send EDP packets even if no EDP peer detected"
+msgstr "Отправлять EDP пакеты даже если не обнаружено соседей с EDP протоколом"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:525
+msgid "Send FDP packets even if no FDP peer detected"
+msgstr "Отправлять FDP пакеты даже если не обнаружено соседей с FDP протоколом"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:571
+msgid "Send SONMP packets even if no SONMP peer detected"
+msgstr ""
+"Отправлять SONMP пакеты даже если не обнаружено соседей с SONMP протоколом"
+
+#: applications/luci-app-lldpd/root/usr/share/luci/menu.d/luci-app-lldpd.json:28
+msgid "Settings"
+msgstr "Настройки"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:402
+msgid "Specify the behaviour when detecting multiple neighbors"
+msgstr "Поведение при обнаружении нескольких соседей"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:274
+msgid ""
+"Specify which interface (not) to listen upon and send LLDPDU from. Absent "
+"any value, LLDPd uses all available physical interfaces."
+msgstr ""
+"Укажите какие интерфейсы должны прослушивать и отправлять LLDPDU. Если "
+"интерфейсы не указаны, LLDPd будет использовать все доступные физические "
+"интерфейсы."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:290
+msgid ""
+"Specify which interfaces (not) to use for computing chassis ID. Absent any "
+"value, all interfaces are considered. LLDPd takes the first MAC address from "
+"all the considered interfaces to compute the chassis ID."
+msgstr ""
+"Укажите какие интерфейсы необходимо использовать для вычисления "
+"идентификатора шасси (chassis ID). Если интерфейсы не указаны, будут "
+"иcпользованы все интерфейсы. LLDPd получит первый MAC-адрес из всех "
+"доступных интерфейсов для вычисления ID шасси."
+
+#: applications/luci-app-lldpd/root/usr/share/luci/menu.d/luci-app-lldpd.json:16
+msgid "Status"
+msgstr "Состояние"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:215
+msgid "Suffix %s for millisecond values."
+msgstr "Прибавляй суффикс %s для значений миллисекунд."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:159
+msgid "System capabilities"
+msgstr "Системные возможности"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:153
+msgid "System capability advertisements"
+msgstr "Объявления системных возможност"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:116
+msgid "System description"
+msgstr "Описание системы"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:123
+msgid "System hostname"
+msgstr "Имя системы"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:185
+msgid "System management IO"
+msgstr "Адреса управления данной системы"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:178
+msgid "System management IO advertisements"
+msgstr "Объявления адресов управления данной системы"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:147
+msgid "System platform description"
+msgstr "Описание платформы"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:228
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:230
+msgid "TTL"
+msgstr "TTL"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:149
+msgid "The default description is the kernel name (Linux)."
+msgstr "По умолчанию используется имя используемого ядра (Linux)."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:403
+msgid "The default filter is 15. Refer to "FILTERING NEIGHBORS"."
+msgstr ""
+"По умолчанию используется фильтр 15. Более подробную информацию о данной "
+"опции можно посмотреть в разделе «FILTERING NEIGHBORS»."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:161
+msgid "The default is derived from kernel information."
+msgstr "Значение по умолчанию получено из информации о ядре."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:212
+msgid ""
+"The delay between transmissions of LLDP PDU. The default value is 30 seconds."
+msgstr ""
+"Задержка между двумя передачами LLDP PDU. Значение по умолчанию составляет "
+"30 секунд."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:672
+msgid ""
+"This page allows you to see discovered LLDP neighbors, local interfaces "
+"statistics and local chassis information."
+msgstr ""
+"На данной странице вы можете посмотреть таблицу обнаруженных соседей LLDP, "
+"статистику локальных интерфейсов и информацию о локальном шасси."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:211
+msgid "Transmit delay"
+msgstr "Задержка отправки"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:229
+msgid "Transmit hold value"
+msgstr "Значение «transmit hold»"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:244
+msgid "Transmit hold value must be greater than 0"
+msgstr "Значение «transmit hold» должно быть больше 0"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:55
+msgid "Tx"
+msgstr "Tx"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:57
+msgid "Tx discarded"
+msgstr "Tx (отброшено)"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:150
+msgid "Tx only"
+msgstr "Только Tx"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:154
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:262
+msgid "Unknown"
+msgstr "Неизвестно"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:411
+msgid ""
+"With this option, you can force the port identifier to be the interface name "
+"or the MAC address."
+msgstr ""
+"Данная настройка позволяет принудительно использовать в качестве "
+"идентификатор порта имя интерфейса или MAC-адрес."
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:307
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:316
+msgid "disabled"
+msgstr "выключено"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:46
+msgid "enable filter"
+msgstr "включить фильтр"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:307
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:316
+msgid "enabled"
+msgstr "включено"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:48
+msgid "keep only one neighbor"
+msgstr "хранить только одного соседа"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:47
+msgid "keep only one protocol"
+msgstr "хранить только один протокол"
--- /dev/null
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:54
+msgid "Administrative Status"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:588
+msgid "Advanced Settings"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:198
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:209
+msgid "Age"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:59
+msgid "Ageout count"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:422
+msgid ""
+"Allows an agent to control the propagation of LLDPDUs. By default, the MAC "
+"address %s is used and limits the propagation of the LLDPDU to the nearest "
+"bridge."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:582
+msgid "Basic Settings"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:464
+msgid ""
+"By default, LLDP packets are sent when there is a peer speaking LLDP "
+"detected or when there is no peer at all."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:475
+msgid "CDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:485
+msgid "CDP version"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:487
+msgid "CDPv1 and CDPv2"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:39
+msgid "Cannot have both interface %s and its exclusion %s"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:319
+msgid "Capabilities"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:46
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:65
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:681
+msgid "Collecting data..."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:335
+msgid "Communication Device Endpoints (Class III)"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:186
+msgid ""
+"Defaults to the first IPv4 and IPv6. If an exact IP address is provided, it "
+"is used as a management address without any check. To blacklist IPv6 "
+"addresses, use <code>!*:*</code>."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:61
+msgid "Delete count"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:273
+msgid "Description"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:230
+msgid ""
+"Determines the transmitted packet TTL (== this value * transmit delay). The "
+"default value is 4 ∴ the default TTL is 120 seconds."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:385
+msgid "Disable LLDP-MED inventory TLV transmission"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:394
+msgid "Disable advertising of kernel release, version and machine"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:152
+msgid "Disabled"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:687
+msgid "Discovered Neighbors"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:41
+msgid "Discovered chassis"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:42
+msgid "Discovered port"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:535
+msgid "EDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:477
+msgid "Enable CDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:537
+msgid "Enable EDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:517
+msgid "Enable FDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:455
+msgid "Enable LLDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:563
+msgid "Enable SONMP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:89
+msgid "Enable service"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:478
+msgid ""
+"Enable the support of CDP protocol to deal with Cisco routers that do not "
+"speak LLDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:538
+msgid ""
+"Enable the support of EDP protocol to deal with Extreme routers and switches "
+"that do not speak LLDP."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:518
+msgid ""
+"Enable the support of FDP protocol to deal with Foundry routers that do not "
+"speak LLDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:564
+msgid ""
+"Enable the support of SONMP protocol to deal with Nortel routers and "
+"switches that do not speak LLDP."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:462
+msgid ""
+"Even when there is no LLDP peer detected but there is a peer speaking "
+"another protocol detected."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:515
+msgid "FDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:162
+msgid "Filter"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:410
+msgid "Force port ID subtype"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:501
+msgid "Force sending CDPv2 packets"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:461
+msgid "Force sending LLDP packets"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:333
+msgid "Generic Endpoint (Class I)"
+msgstr ""
+
+#: applications/luci-app-lldpd/root/usr/share/rpcd/acl.d/luci-app-lldpd.json:18
+msgid "Grant access for LLDP configuration"
+msgstr ""
+
+#: applications/luci-app-lldpd/root/usr/share/rpcd/acl.d/luci-app-lldpd.json:3
+msgid "Grant access for LLDP status information"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:130
+msgid "Host location"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:276
+msgid "ID"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:277
+msgid "ID type"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:116
+msgid "IP address"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:163
+msgid "Incoming"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:60
+msgid "Insert count"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:414
+msgid "Interface MAC address"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:688
+msgid "Interface Statistics"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:415
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:112
+msgid "Interface name"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:395
+msgid ""
+"Kernel name (ie: Linux) will still be shared, and Inventory software version "
+"will be set to %s."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:453
+#: applications/luci-app-lldpd/root/usr/share/luci/menu.d/luci-app-lldpd.json:3
+msgid "LLDP"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:671
+msgid "LLDP Status"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:331
+msgid "LLDP-MED device class"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:373
+msgid "LLDP-MED fast-start"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:377
+msgid "LLDP-MED fast-start tx-interval"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:342
+msgid "LLDP-MED policy"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:421
+msgid "LLDPDU destination MAC"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:598
+msgid "LLDPd Settings"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:599
+msgid "LLDPd is an implementation of IEEE 802.1ab"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:386
+msgid ""
+"LLDPd will still receive (and publish using SNMP if enabled) those LLDP-MED "
+"TLV but will not send them. Use this option if you do not want to transmit "
+"sensitive information like serial numbers."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:251
+msgid "LLDPd won't send any frames; only listen to neighbors."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:676
+msgid "Local Chassis"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:114
+msgid "Local ID"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:39
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:52
+msgid "Local interface"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:110
+msgid "MAC address"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:233
+msgid "MFS"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:295
+msgid "Management IP(s)"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:334
+msgid "Media Endpoint (Class II)"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:223
+msgid "Must be a greater than zero number optionally suffixed with \"ms\""
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:242
+msgid "Must be a number"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:139
+msgid "Must start: 'coordinate ...', 'address ...' or 'elin ...'"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:367
+msgid "Must start: application ..."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:197
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:208
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:270
+msgid "Name"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:336
+msgid "Network Connectivity Device (Class IV)"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:273
+msgid "Network IO"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:289
+msgid "Network IO for chassis ID"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:585
+msgid "Network Interfaces"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:603
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:660
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:664
+msgid "No data to display"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:601
+msgid "On this page you may configure LLDPd parameters."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:488
+msgid "Only CDPv2"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:164
+msgid "Outgoing"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:117
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:124
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:148
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:160
+msgid "Override %s."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:131
+msgid "Override the announced location of the host."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:216
+msgid "Port ID"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:219
+msgid "Port ID type"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:224
+msgid "Port description"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:40
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:53
+msgid "Protocol"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:591
+msgid "Protocols Support"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:250
+msgid "Receive-only mode"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:56
+msgid "Rx"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:146
+msgid "Rx and Tx"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:148
+msgid "Rx only"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:58
+msgid "Rx unrecognized"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:561
+msgid "SONMP (NTDP, NDP, BNMP, BDP)"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:35
+msgid "See syntax <a %s>here</a>."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:494
+msgid "Send CDP packets even if no CDP peer detected"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:545
+msgid "Send EDP packets even if no EDP peer detected"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:525
+msgid "Send FDP packets even if no FDP peer detected"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:571
+msgid "Send SONMP packets even if no SONMP peer detected"
+msgstr ""
+
+#: applications/luci-app-lldpd/root/usr/share/luci/menu.d/luci-app-lldpd.json:28
+msgid "Settings"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:402
+msgid "Specify the behaviour when detecting multiple neighbors"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:274
+msgid ""
+"Specify which interface (not) to listen upon and send LLDPDU from. Absent "
+"any value, LLDPd uses all available physical interfaces."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:290
+msgid ""
+"Specify which interfaces (not) to use for computing chassis ID. Absent any "
+"value, all interfaces are considered. LLDPd takes the first MAC address from "
+"all the considered interfaces to compute the chassis ID."
+msgstr ""
+
+#: applications/luci-app-lldpd/root/usr/share/luci/menu.d/luci-app-lldpd.json:16
+msgid "Status"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:215
+msgid "Suffix %s for millisecond values."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:159
+msgid "System capabilities"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:153
+msgid "System capability advertisements"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:116
+msgid "System description"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:123
+msgid "System hostname"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:185
+msgid "System management IO"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:178
+msgid "System management IO advertisements"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:147
+msgid "System platform description"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:228
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:230
+msgid "TTL"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:149
+msgid "The default description is the kernel name (Linux)."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:403
+msgid "The default filter is 15. Refer to "FILTERING NEIGHBORS"."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:161
+msgid "The default is derived from kernel information."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:212
+msgid ""
+"The delay between transmissions of LLDP PDU. The default value is 30 seconds."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:672
+msgid ""
+"This page allows you to see discovered LLDP neighbors, local interfaces "
+"statistics and local chassis information."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:211
+msgid "Transmit delay"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:229
+msgid "Transmit hold value"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:244
+msgid "Transmit hold value must be greater than 0"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:55
+msgid "Tx"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:57
+msgid "Tx discarded"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:150
+msgid "Tx only"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:154
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:262
+msgid "Unknown"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/config.js:411
+msgid ""
+"With this option, you can force the port identifier to be the interface name "
+"or the MAC address."
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:307
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:316
+msgid "disabled"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:46
+msgid "enable filter"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:307
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/view/lldpd/status.js:316
+msgid "enabled"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:48
+msgid "keep only one neighbor"
+msgstr ""
+
+#: applications/luci-app-lldpd/htdocs/luci-static/resources/lldpd.js:47
+msgid "keep only one protocol"
+msgstr ""
--- /dev/null
+{
+ "admin/services/lldpd": {
+ "title": "LLDP",
+ "order": 80,
+ "action": {
+ "type": "firstchild"
+ },
+ "depends": {
+ "uci": {
+ "lldpd": true
+ }
+ }
+ },
+
+ "admin/services/lldpd/status": {
+ "title": "Status",
+ "order": 10,
+ "action": {
+ "type": "view",
+ "path": "lldpd/status"
+ },
+ "depends": {
+ "acl": [ "luci-app-lldpd-status" ]
+ }
+ },
+
+ "admin/services/lldpd/config": {
+ "title": "Settings",
+ "order": 20,
+ "action": {
+ "type": "view",
+ "path": "lldpd/config"
+ },
+ "depends": {
+ "acl": [ "luci-app-lldpd-config" ]
+ }
+ }
+}
--- /dev/null
+{
+ "luci-app-lldpd-status": {
+ "description": "Grant access for LLDP status information",
+ "read": {
+ "ubus": {
+ "luci.lldpd": [
+ "getStatus"
+ ]
+ },
+ "uci": [
+ "lldpd",
+ "luci"
+ ]
+ }
+ },
+
+ "luci-app-lldpd-config": {
+ "description": "Grant access for LLDP configuration",
+ "read": {
+ "uci": [
+ "lldpd"
+ ],
+ "ubus": {
+ "luci.lldpd": [
+ "getStatus"
+ ],
+ "luci": [
+ "getInitList"
+ ]
+ }
+ },
+ "write": {
+ "uci": [
+ "lldpd"
+ ],
+ "ubus": {
+ "luci": [
+ "setInitAction"
+ ]
+ }
+ }
+ }
+}
--- /dev/null
+'use strict';
+
+import { popen } from 'fs';
+
+function lldpcli_json(section) {
+ return json(popen(`lldpcli -f json0 show ${section}`, 'r'));
+}
+
+return {
+ 'luci.lldpd': {
+ getStatus: {
+ call: function() {
+ return {
+ statistics: lldpcli_json("statistics"),
+ neighbors: lldpcli_json("neighbors details"),
+ interfaces: lldpcli_json("interfaces"),
+ chassis: lldpcli_json("chassis")
+ };
+ }
+ }
+ }
+};